package com.zusmart.base.thread;

import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;
import java.nio.charset.CharsetEncoder;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.IdentityHashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;

import com.zusmart.base.activity.support.AbstractAttachable;
import com.zusmart.base.util.GenericUtils;

public class FastThreadLocal extends AbstractAttachable<Object, Object> {

	private static final int maxIndexedVarsSize = 32;
	private static final AtomicInteger indexedVarsIndex = new AtomicInteger(0);
	private static final ThreadLocal<FastThreadLocal> slowThreadLocal = new ThreadLocal<FastThreadLocal>();

	private byte[] bytes32 = new byte[32];
	private Map<Charset, CharsetDecoder> charsetDecoders = new IdentityHashMap<Charset, CharsetDecoder>();
	private Map<Charset, CharsetEncoder> charsetEncoders = new IdentityHashMap<Charset, CharsetEncoder>();
	private Object[] indexedVariables = new Object[maxIndexedVarsSize];
	private StringBuilder stringBuilder = new StringBuilder(512);

	public byte[] getBytes32() {
		return bytes32;
	}

	public CharsetDecoder getCharsetDecoder(Charset charset) {
		CharsetDecoder decoder = charsetDecoders.get(charset);
		if (decoder == null) {
			decoder = charset.newDecoder();
			this.charsetDecoders.put(charset, decoder);
		}
		return decoder;
	}

	public CharsetEncoder getCharsetEncoder(Charset charset) {
		CharsetEncoder encoder = charsetEncoders.get(charset);
		if (encoder == null) {
			encoder = charset.newEncoder();
			this.charsetEncoders.put(charset, encoder);
		}
		return encoder;
	}

	public Object getIndexedVariable(int index) {
		return this.indexedVariables[index];
	}

	public List<Object> getList(int index) {
		List<Object> list = GenericUtils.parse(this.getIndexedVariable(index));
		if (list == null) {
			list = new ArrayList<Object>();
			this.setIndexedVariable(index, list);
		}
		list.clear();
		return list;
	}

	public Map<Object, Object> getMap(int index) {
		Map<Object, Object> map = GenericUtils.parse(this.getIndexedVariable(index));
		if (map == null) {
			map = new HashMap<Object, Object>();
			this.setIndexedVariable(index, map);
		}
		map.clear();
		return map;
	}

	public StringBuilder getStringBuilder() {
		this.stringBuilder.setLength(0);
		return stringBuilder;
	}

	public void setIndexedVariable(int index, Object value) {
		this.indexedVariables[index] = value;
	}

	public static void destroy() {

	}

	public static FastThreadLocal get() {
		Thread thread = Thread.currentThread();
		if (thread instanceof FastThread) {
			return ((FastThread) thread).getThreadLocal();
		} else {
			FastThreadLocal l = slowThreadLocal.get();
			if (l == null) {
				l = new FastThreadLocal();
				slowThreadLocal.set(l);
			}
			return l;
		}
	}

	public static int nextIndexedVariablesIndex() {
		if (indexedVarsIndex.get() >= maxIndexedVarsSize) {
			return -1;
		}
		int index = indexedVarsIndex.getAndIncrement();
		if (index >= maxIndexedVarsSize) {
			return -1;
		}
		return index;
	}

}